﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using NetJsWire.Lite.Converters;
using NetJsWire.Lite.Editors;
using NetJsWire.Lite.Widgets.UI.Util;
using Newtonsoft.Json;

namespace NetJsWire.Lite.Widgets.UI.Data
{
    [Designer( typeof( ComponentDesigner ) )]
    [JsonObject( MemberSerialization = MemberSerialization.OptIn )]
    public class Store : BaseObservable //, IWidget
    {
        private FieldCollection _fields = new FieldCollection();
        private SortInfo _sortInfo = new SortInfo();

        ///<summary>
        ///  Initializes a new instance of Store.
        ///</summary>
        public Store()
            : this( null )
        {
        }

        ///<summary>
        ///  Initializes a new instance of Store and adds it to the Container.
        ///</summary>
        ///<param name = "container"></param>
        public Store( IContainer container )
        {
            if ( container != null )
                container.Add( this );
            Xtype = "arraystore";
            AutoSave = true;
        }

        [JsonProperty( "autoDestroy", DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( false )]
        [Description( "true to destroy the store when the component the store is bound to is destroyed.\n(Note: this should be set to true when using stores that are bound to only 1 component.)" )]
        public bool AutoDestroy { get; set; }

        [JsonProperty( "autoLoad", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( false )]
        [Description( "If data is not specified, and if autoLoad is true or an Object, this store's load method is automatically called after creation. If the value of autoLoad is an Object, this Object will be passed to the store's load method." )]
        public bool AutoLoad { get; set; }

        [JsonProperty( "autoSave", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( true )]
        [Description( "Defaults to true causing the store to automatically save records to the server when a record is modified (ie: becomes 'dirty'). Specify false to manually call save to send all modifiedRecords to the server.\nNote: each CRUD action will be sent as a separate request." )]
        public bool AutoSave { get; set; }

        [JsonProperty( "baseParams", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "An object containing properties which are to be sent as parameters for every HTTP request.\nParameters are encoded as standard HTTP parameters using Ext.urlEncode." )]
        public string BaseParams { get; set; }

        [JsonProperty( "batch", DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( false )]
        [Description( "Defaults to true (unless restful:true). Multiple requests for each CRUD action (CREATE, READ, UPDATE and DESTROY) will be combined and sent as one transaction. Only applies when autoSave is set to false." )]
        public bool Batch { get; set; }

        [JsonProperty( "data", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [Description( "An inline data object readable by the Reader. Typically this option, or the url option will be specified." )]
        [TypeConverter( typeof( StringConverter ) )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        public object Data { get; set; }

        [JsonProperty( "fields" )]
        [DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
        [Description( "" )]
        public virtual FieldCollection Fields
        {
            get { return _fields; }
            set { _fields = value; }
        }

        [JsonProperty( "paramNames", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        [Description( "An object containing properties which specify the names of the paging and sorting parameters passed to remote servers when loading blocks of data." )]
        public string ParamNames { get; set; }

        [JsonProperty( "proxy", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( null )]
        [Description( "The DataProxy object which provides access to a data object." )]
        public virtual DataProxy Proxy { get; set; }

        [JsonProperty( "pruneModifiedRecords", DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( false )]
        [Description( "true to clear all modified record information each time the store is loaded or when a record is removed (defaults to false)." )]
        public bool PruneModifiedRecords { get; set; }

        [JsonProperty( "reader", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( null )]
        [Description( "The Reader object which processes the data object and returns an Array of Ext.data.Record objects which are cached keyed by their id property." )]
        public virtual DataReader Reader { get; set; }

        [JsonProperty( "remoteSort", DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( false )]
        [Description( "true if sorting is to be handled by requesting the Proxy to provide a refreshed version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false)." )]
        public bool RemoteSort { get; set; }

        [JsonProperty( "restful", DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( false )]
        [Description( "Defaults to false. Set to true to have the Store and the set Proxy operate in a RESTful manner. The store will automatically generate GET, POST, PUT and DELETE requests to the server." )]
        public bool Restful { get; set; }

        [JsonProperty( "sortInfo", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [TypeConverter( typeof( ExpandableObjectConverter ) )]
        [Description( "" )]
        public SortInfo SortInfo
        {
            get
            {
                return _sortInfo;
            }
            set { _sortInfo = value; }
        }

        [JsonProperty( "storeId", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        [Description( "If passed, the id to use to register with the StoreMgr." )]
        public string StoreId { get; set; }

        [JsonProperty( "url", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        [Description( "If a proxy is not specified the url will be used to implicitly configure a HttpProxy if an url is specified. Typically this option, or the data option will be specified." )]
        public string Url { get; set; }

        [JsonProperty( "writer", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( null )]
        [Description( "" )]
        public DataWriter Writer { get; set; }

        [JsonProperty( "xtype", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Include )]
        [DefaultValue( "arraystore" )]
        [Description( "" )]
        [TypeConverter( typeof( XtypeTypeConverter ) )]
        public virtual string Xtype { get; set; }

        [JsonProperty( "messageProperty" )]
        [DefaultValue( ( string ) null )]
        public string MessageProperty { get; set; }

        ////[DefaultValue( ( string ) null ), AttributeProvider( typeof( IListSource ) ), RefreshProperties( RefreshProperties.Repaint )]
        //[Editor( typeof( StoreBindingTypeEditor ), typeof( UITypeEditor ) )]
        //[EditorBrowsable( EditorBrowsableState.Never )]
        //public object AutoConfigureWith
        //{
        //    get { return null; }
        //    set
        //    {
        //        if ( value != null )
        //        {
        //            Fields.Clear();

        //            var props = ( ( Type ) value ).GetProperties();
        //            foreach ( var prop in props )
        //            {
        //                var field = GetDataFieldFromType( prop.PropertyType );
        //                field.Name = prop.Name;
        //                Fields.Add( field );
        //            }
        //        }
        //    }
        //}

        public bool ShouldSerializeData()
        {
            return Data != null && !string.IsNullOrEmpty( Data.ToString() );
        }

        public void ResetData()
        {
            Data = null;
        }

        public bool ShouldSerializeFields()
        {
            return Fields.Count > 0;
        }

        protected void ResetFields()
        {
            Fields.Clear();
        }

        public bool ShouldSerializeSortInfo()
        {
            return !string.IsNullOrWhiteSpace( SortInfo.Direction ) || !string.IsNullOrWhiteSpace( SortInfo.Field );
        }

        protected void ResetSortInfo()
        {
            SortInfo.Direction = null;
            SortInfo.Field = null;
        }

        //[Browsable( false )]
        //public virtual IRenderer Renderer
        //{
        //    get { return _renderer; }
        //}

        //public void On( string name, string function )
        //{
        //    Renderer.AddClientEvent( name, function );
        //}

        //public void AddClass( string cls )
        //{
        //    throw new NotSupportedException( "This component does not support this method." );
        //}

        //public void RemoveClass( string cls )
        //{
        //    throw new NotSupportedException( "This component does not support this method." );
        //}

        //[Browsable( false )]
        //[DefaultValue( false )]
        //[Description( "If the framework should generate a global Javascript variable that points to the Widget, the name of the variable will be the same as ClientID property of the Renderer." )]
        //public bool GenerateClientMember { get; set; }

        //private IConfigOptions _configOptions;
        //[RefreshProperties( RefreshProperties.All )]
        //[DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
        //[Category( "Config" )]
        //[Browsable( false )]
        //public virtual IConfigOptions ConfigOptions
        //{
        //    get { return _configOptions ?? ( _configOptions = new StoreConfigOptions( this ) ); }
        //}

        private static Field GetDataFieldFromType( Type type )
        {
            var field = new Field();
            if ( type.Equals( typeof( string ) ) )
            {
                field.Type = "string";
            }
            if ( type.Equals( typeof( bool ) ) )
            {
                field.Type = "boolean";
            }
            if ( typeof( DateTime ).IsAssignableFrom( type ) || typeof( DateTime? ).IsAssignableFrom( type ) )
            {
                field.Type = "date";
            }
            if ( type == typeof( Int16 ) ||
                  type == typeof( Int32 ) ||
                  type == typeof( Int64 ) ||
                  type == typeof( UInt16 ) ||
                  type == typeof( UInt32 ) ||
                  type == typeof( UInt64 ) )
            {
                field.Type = "int";
            }
            if ( type == typeof( Single ) || type == typeof( Double ) || type == typeof( Decimal ) )
            {
                field.Type = "float";
            }

            return field;
        }

        #region Miembros de IListSource

        [Browsable( false )]
        public bool ContainsListCollection
        {
            get { return Data != null && Data.GetType().IsAssignableFrom( typeof( IList ) ); }
        }

        public IList GetList()
        {
            return null;
        }

        #endregion
    }

    [TypeConverter( typeof( ExpandableObjectConverter ) )]
    [JsonObject( MemberSerialization = MemberSerialization.OptIn )]
    public class SortInfo
    {
        private string _direction = string.Empty;
        private string _field = string.Empty;
        [JsonProperty( "field", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        public string Field
        {
            get { return _field; }
            set { _field = value; }
        }

        [JsonProperty( "direction", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        public string Direction
        {
            get { return _direction; }
            set { _direction = value; }
        }
    }
}
